<?php
//+----------------------------------------------------------------------
//| ThinkPHP [ WE CAN DO IT JUST THINK IT ]
//+----------------------------------------------------------------------
//| Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
//+----------------------------------------------------------------------
//| Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
//+----------------------------------------------------------------------
//| Author: liu21st <liu21st@gmail.com>
//+----------------------------------------------------------------------
//$Id: Action.class.php 2791 2012-02-29 10:08:57Z liu21st $
/**
 +------------------------------------------------------------------------------
 * ThinkPHP Action控制器基类 抽象类
 +------------------------------------------------------------------------------
 * @category   Think
 * @package  Think
 * @subpackage  Core
 * @author   liu21st <liu21st@gmail.com>
 * @version  $Id: Action.class.php 2791 2012-02-29 10:08:57Z liu21st $
 * @last modify 2012-12-04 17:17:43 by mashanling
 +------------------------------------------------------------------------------
 */
abstract class Action {
    protected $view = null;//视图实例对象
    private   $name = '';  //当前Action名称

    /**
     * 默认跳转操作 支持错误导向和正确跳转
     * 调用模板显示 默认为public目录下面的success页面
     * 提示页面为可配置 支持模板标签
     *
     * @last modify 2012-12-04 17:18:16 by mashanling
     *
     * @access private
     *
     * @param string $message  提示信息
     * @param bool   $status   状态
     * @param string $jump_url 页面跳转地址
     * @param bool   $ajax     是否为Ajax方式
     *
     * @return void 无返回值
     */
    private function dispatchJump($message = '', $status = 1, $jump_url = '', $ajax = false) {

        if ($ajax || $this->isAjax()) {//判断是否为AJAX返回
            $this->ajaxReturn($ajax, $message, $status);
        }

        !empty($jump_url) && $this->assign('jump_url', $jump_url);
        //提示标题
        //$this->assign('msgTitle',$status? L('_OPERATION_SUCCESS_') : L('_OPERATION_FAIL_'));
        //如果设置了关闭窗口，则提示完毕后自动关闭窗口
        $this->view->get('closeWin') && $this->assign('jump_url', 'javascript:window.close();');
        $this->assign('status', $status); //状态
        C('HTML_CACHE_ON', false);//保证输出不受静态缓存影响

        if ($status) {//发送成功信息
            $this->assign('message', $message); //提示信息
            !$this->view->get('waitSecond') && $this->assign('waitSecond', 1);//成功操作后默认停留1秒
            !$this->view->get('jump_url') && $this->assign('jump_url', $_SERVER['HTTP_REFERER']);//默认操作成功自动返回操作前页面
            $this->display(C('TMPL_ACTION_SUCCESS'));
        }
        else {
            $this->assign('error', $message); //提示信息
            !$this->view->get('waitSecond') && $this->assign('waitSecond', 3);//发生错误时候默认停留3秒
            !$this->view->get('jump_url') && $this->assign('jump_url', $_SERVER['HTTP_REFERER']);//默认发生错误的话自动返回上页
            $this->display(C('TMPL_ACTION_ERROR'));
        }

        exit();//中止执行  避免出错后继续执行
    }//end dispatchJump

    /**
     * Ajax方式返回数据到客户端
     *
     * @last modify 2012-12-04 17:36:19 by mashanling
     *
     * @access protected
     *
     * @param mixed  $success 返回状态或返回数组
     * @param string $msg     提示信息
     * @param mixed  $data    要返回的数据
     * @param string $type    ajax返回类型 JSON XML等
     *
     * @return void 无返回值
     */
    protected function ajaxReturn($success = true, $msg = '', $data = null, $type = '') {

        if (is_array($success)) {
            $result = $success;
        }
        else {
            $result = array();
            $result['success'] = $success;
            $result['msg']     = $msg;
            $result['data']    = $data;
        }

        $result['time'] = round(microtime(true) - REQUEST_TIME_MICRO, 6);

        //扩展ajax返回数据, 在Action中定义function ajaxAssign(&$result){} 方法 扩展ajax返回数据。
        method_exists($this, 'ajaxAssign') && $this->ajaxAssign($result);

        $type = strtoupper($type ? $type : C('DEFAULT_AJAX_RETURN'));

        if ('JSON' == $type) {//返回JSON数据格式到客户端 包含状态信息
            header('Content-Type: application/json; charset=utf-8');
            $this->__get__ && exit(var_export($result, true)); //调试模式下，不需要json_encode，以可读 by mashanling on 2012-07-12 09:25:22

            $result = json_encode($result);
            $v      = C('JSONP_CALLBACK');

            if ($v && isset($_GET[$v])) {//jsonp by mashanling on 2012-12-04 17:33:46
                $result = $_GET[$v] . '(' . $result . ')';
            }

            exit($result);
        }
        elseif ('XML' == $type) {//返回xml格式数据
            header('Content-Type: text/xml; charset=utf-8');
            exit(xml_encode($result));
        }
        elseif ('EVAL' == $type) {//返回可执行的js脚本
            header('Content-Type: text/html; charset=utf-8');
            exit($data);
        }
        //TODO 增加其它格式
        else {}
    }//end ajaxReturn

    /**
     * 操作错误跳转的快捷方法
     *
     * @last modify 2012-12-04 18:19:08 by mashanling
     *
     * @access protected
     *
     * @param string $message  错误信息
     * @param string $jump_url 页面跳转地址
     * @param bool   $ajax     是否为Ajax方式
     *
     * @return mixed $this->dispatchJump()结果
     */
    protected function error($message = '操作失败', $jump_url = '', $ajax = false) {
        $this->dispatchJump($message, 0, $jump_url, $ajax);
    }

    /**
     * 获取当前操作名称
     *
     * @last modify 2012-12-04 18:22:07 by mashanling
     *
     * @access protected
     *
     * @return string 当前操作名称
     */
    protected function getActionName() {
        $this->name = $this->name ? $this->name : substr(get_class($this), 0, - 6);

        return $this->name;
    }

     /**
     * 判断是否AJAX请求
     *
     * @last modify 2012-12-05 11:40:55 by mashanling
     *
     * @access protected
     *
     * @return bool 如果是ajax请求，返回true，否则返回false
     */
    protected function isAjax() {

        if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 'xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])) {
            return true;
        }
        elseif (!empty($_POST[$v = C('VAR_AJAX_SUBMIT')]) || !empty($_GET[$v])) {//判断Ajax方式提交
            return true;
        }

        return false;
    }

    /**
     * url跳转
     *
     * @last modify 2012-12-05 11:49:14 by mashanling
     *
     * @param string $url         跳转url，默认网站首页
     * @param string $base_url    基链接
     * @param int    $status_code 头部状态码，默认0，不发送头部状态码
     *
     * @return void 无返回值
     */
    protected function redirect($url = '', $base_url = null, $status_code = 0) {
        $url = null === $base_url ? to_website_url('/') . $url : $base_url . $url;
        redirect($url, 0, '', $status_code);
    }

    /**
     * 发送http状态信息
     *
     * @author       mashanling(msl-138@163.com)
     * @date         8:39 2012/7/8
     * @last modify  2012-12-03 14:08:02 by mashanling
     *
     * @param int    $code 状态码
     * @param string $msg  自定义状态信息
     *
     * @return object 本类实例对象
     */
    protected function sendHttpStatus($code, $msg = '') {
        send_http_status($code, $msg);

        return $this; //返回本类实例对象 by mashanling on 2012-07-10 11:25:53
    }

    /**
     * 操作成功跳转的快捷方法
     *
     * @last modify 2012-12-04 18:19:08 by mashanling
     *
     * @access protected
     *
     * @param string $message  成功信息
     * @param string $jump_url 页面跳转地址
     * @param bool   $ajax     是否为Ajax方式
     *
     * @return mixed $this->dispatchJump()结果
     */
    protected function success($message = '操作成功', $jump_url = '', $ajax = false) {
        $this->dispatchJump($message, 1, $jump_url, $ajax);
    }

    /**
     * 魔术方法 有不存在的操作的时候执行
     *
     * @last modify 2012-12-06 13:32:52 by mashanling
     *
     * @access public
     *
     * @param string $method 方法名
     * @param array  $args   参数
     *
     * @return mixed
     */
    public function __call($method, $args) {
        if (0 === strcasecmp($method, ACTION_NAME)) {

            if (method_exists($this, '_empty')) {//如果定义了_empty操作 则调用
                return $this->_empty($method, $args);
            }
            elseif (file_exists_case(C('TEMPLATE_NAME'))) {//检查是否存在默认模版 如果有直接输出模版
                return $this->display();
            }
            elseif (function_exists('__hack_action')) {//hack 方式定义扩展操作
                return __hack_action();
            }
        }

        if (method_exists($this->view, $method)) {//调用视图模板方法 by mashanling on 2012-12-06 09:02:32
            return call_user_func_array(array(&$this->view, $method), $args);
        }
        elseif (APP_DEBUG) {//抛出异常
            throw new Exception(L('_ERROR_ACTION_') . ACTION_NAME);
        }

        trigger_error(L('_ERROR_ACTION_') . ACTION_NAME, E_USER_ERROR);
        send_http_status(404);
        exit();
    }

    /**
     *
     * 架构函数
     *
     * @last modify 2012-12-05 11:51:56 by mashanling
     *
     * @access public
     *
     * @return void 无返回值
     */
    public function __construct() {
        tag('action_begin');
        $this->view = Think::instance('View');//实例化视图类
        method_exists($this, '_initialize') && $this->_initialize();//控制器初始化
    }

    /**
     *
     * 析构函数
     *
     * @last modify 2012-12-05 11:52:39 by mashanling
     *
     * @access public
     *
     * @return void 无返回值
     */
    public function __destruct() {
        Log::save();//保存日志
        tag('action_end');//执行后续操作
    }

    /**
     * 获取属性值
     *
     * @last modify 2012-12-05 16:36:59 by mashanling
     *
     * @access public
     *
     * @param string $name 属性名称
     *
     * @return mixed 属性值或空字符串
     */
    public function __get($name) {
        return property_exists($this, $name) ? $this->$name : '';
    }

    /**
     * 设置属性值
     *
     * @last modify 2012-12-05 16:37:38 by mashanling
     *
     * @access public
     *
     * @param string $name  属性名称
     * @param mixed  $value 属性值
     *
     * @return mixed 属性值或空字符串
     */
    public function __set($name, $value) {
        $this->$name = $value;

        return $this;
    }

    /**
     * 获取视图或视图属性值
     *
     * @last modify 2012-12-05 16:37:38 by mashanling
     *
     * @access public
     *
     * @param string $property  属性名称
     *
     * @return mixed 如果设置$property，返回该属性值，否则返回视图实例
     */
    function getView($property = false) {
        $view = $this->view;
        return $property ? $view->{$property} : $view;
    }
}